Jetpack Compose for Web をやってみた
はじめに
JetPack Compose で Web 対応がでてきましたね。
マルチプラットフォーム系だと他にも Flutter、 React Native などがあり、バチバチの覇権争いが起こっていて、まだまだどれも発展途上で破壊的な変更やパラダイムシフトも多いとは思いますが面白い時期だと思います。
Jetpack Compose for Web
Kotlin Multiplatform の最大の難所は Gradle の設定だと思う。Web のみで素朴に Run できて Build できてから、Multiplatform 部分に挑戦したほうが良いと思います。
あまり Gradle の設定部分でハマりたくないので、本記事ではチュートリアルのままでやります。
このチュートリアルでの完成品はこれになります。ハマったらこちらを参考にしよう。
プロジェクト作成
Intellj IDEA からプロジェクト作成します。
GradleプロジェクトからKotlin/Multiplatformを選びます。罠としてはKotlinの項目からKotlin/Multiplatformを選ぶとGradle力がない人は詰みます。KMMおいては、下手にステップしない。まず素朴に背伸びしない。
チュートリアルでは Gradle を Kotlin DSL で選ぶようになっています。kts での情報がまだまだ少ないのではまりやすいかもしれないですが、頑張ろう。
settings.gradle.kts の設定
rootProject.name = "jetpack-compose-web" pluginManagement { repositories { gradlePluginPortal() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") } }
注意としては、rootProject.nameは消さずに追記します。
AndroidのGradleの設定をしていると、settings.gradle.ktsにrepositoriesの設定をするんだっと言った感じ。 そして俺たちは Gradle を雰囲気で設定している。
build.gradle.kts の設定
// Add compose gradle plugin plugins { kotlin("multiplatform") version "1.4.32" id("org.jetbrains.compose") version "0.0.0-web-dev-11" } // Add maven repositories repositories { mavenCentral() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") } // Enable JS(IR) target and add dependencies kotlin { js(IR) { browser() binaries.executable() } sourceSets { val jsMain by getting { dependencies { implementation(compose.web.web) implementation(compose.runtime) } } } }
下手に差分を追記しようとしない。ここは全部上のに入れ替える。全コピペ。
また背伸びしてKotlin 1.5.0にした君!またやっちゃったね。のちにエラーになるけど、1.4.32じゅないと動かないよ。
This version (1.0.0-beta06) of the Compose Compiler requires Kotlin version 1.4.32 but you appear to be using Kotlin version 1.5.0 which is not known to be compatible.
ソースコードとリソースのフォルダを作る
以下のフォルダを作成する。srcすら最初ないので、すべて自分で作成する。
- src/jsMain/kotlin
- src/jsMain/resources
index.htmlを作成する
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Sample</title> </head> <body> <div id="root"></div> <script src="REPLACE_WITH_YOUR_MODULE_NAME.js"></script> </body> </html>
<script src="REPLACE_WITH_YOUR_MODULE_NAME.js"></script>
ここ何を設定したらええの?ってなるけど、たぶんだけど、./settings.gradle.kts
で設定したrootProject.name
のjetpack-compose-web
を設定するんだと思う。
そして俺たちは Gradle を雰囲気で...(ry
Main.ktを作成する。
index.html
の <div id="root"></div>
の部分をJSでレンダーする部分をMain.ktで記述する。
チュートリアルではimportの記述がないのでハマる。完成品のほうみて頑張る。
みんな大好きな保管がきかないので、importが alt enter
のauto fixができなくて死ぬ。
import androidx.compose.runtime.mutableStateOf import androidx.compose.web.css.padding import androidx.compose.web.css.px import androidx.compose.web.elements.Button import androidx.compose.web.elements.Div import androidx.compose.web.elements.Span import androidx.compose.web.elements.Text import androidx.compose.web.renderComposable fun main() { val count = mutableStateOf(0) renderComposable(rootElementId = "root") { Div(style = { padding(25.px) }) { Button(attrs = { onClick { count.value = count.value - 1 } }) { Text("-") } Span(style = { padding(15.px) }) { Text("${count.value}") } Button(attrs = { onClick { count.value = count.value + 1 } }) { Text("+") } } } }
補足: コード補完を使うために
Gradle のSyncをいくらしてもソースコードのindexが走らないので、これが最小手順がかわらないが以下の通り。
そして俺たちは Gradle を雰囲気で...(ry
動かなくてよいので、Runのコマンドを叩きライブラリとかをダウンロードさせる
$ ./gradlew jsBrowserRun
src/jsMain/kotlinをソースコードのフォルダだとIDEに認識させる
IDE再起動する
indexが走って保管が効くようになるはず。importをalt enterで追加してくれます。
ブラウザで実行する
$ ./gradlew jsBrowserRun
http://localhost:8080/ でアクセスできるようになる。
公開用にビルドする
$ ./gradlew jsBrowserProductionWebpack
ビルドの成果物はbuild/distributionsに置かれる。
build/distributions ├── index.html ├── jetpack-compose-web.js └── jetpack-compose-web.js.map
補足: ポート番号かえたい!
ビルドでWebpackを使っているぽい。jsBrowserRunではwebpack-dev-serverを使っているのかな。
port番号を8080から他のポート(ex:3000)に変えたい場合は以下のようにする
... kotlin { js(IR) { browser { runTask { devServer = devServer?.copy(port = 3000) } } binaries.executable() } ... }
まとめ
出たてでまだまだハマりどころがあるけど、面白いね。各マルチプラットフォームの戦略も違うので楽しいと思う。最近Reactばっかりだけど、元AndroiderとしてKMMも定点観測していこう。